package main

import "fmt"

type VehicleType int

const (
	UNKNOWN VehicleType = iota
	MOTORCYCLE
	CAR
	BUS
)

func main() {
	test2()
}

func test1() {
	parkingLot := NewParkingLot(1, 1, 11)
	car := NewCar()
	bus := NewBus()
	a1 := parkingLot.ParkVehicle(NewMotorcycle())
	a2 := parkingLot.ParkVehicle(NewCar())
	a3 := parkingLot.ParkVehicle(NewCar())
	a4 := parkingLot.ParkVehicle(NewCar())
	a5 := parkingLot.ParkVehicle(NewCar())
	a6 := parkingLot.ParkVehicle(car)
	a7 := parkingLot.ParkVehicle(bus)
	parkingLot.UnparkVehicle(car)
	a8 := parkingLot.ParkVehicle(bus)
	println(a1)
	println(a2)
	println(a3)
	println(a4)
	println(a5)
	println(a6)
	println(a7)
	println(a8)
}
func test2() {
	parkingLot := NewParkingLot(2, 3, 7)
	car := NewCar()
	bus := NewBus()
	a1 := parkingLot.ParkVehicle(NewMotorcycle())
	a2 := parkingLot.ParkVehicle(NewCar())
	a3 := parkingLot.ParkVehicle(NewBus())
	a4 := parkingLot.ParkVehicle(NewCar())
	a5 := parkingLot.ParkVehicle(NewCar())
	a6 := parkingLot.ParkVehicle(car)
	a7 := parkingLot.ParkVehicle(bus)
	parkingLot.UnparkVehicle(car)
	a8 := parkingLot.ParkVehicle(bus)
	println(a1)
	println(a2)
	println(a3)
	println(a4)
	println(a5)
	println(a6)
	println(a7)
	println(a8)
}

type ParkingLot struct {
	levels []*Level // 层数
}

type Level struct {
	n      int                 // 第几层
	row    int                 // 第几行
	column int                 // 第几列
	spots  map[string]*Vehicle // 第几行第几列停的什么车
}

type Vehicle struct {
	vType  VehicleType
	vSize  int
	vLevel *Level
	// 车子的坐标（停在了第几行第几列,一个车可能占了几个位置），因此用数组记录，示例[]{"2,3","2,4"}
	vRowColumns []string
	getRange    GetRangeF
}
type GetRangeF func(k int) []int

//type Motorcycle struct {
//	Vehicle
//}
//type Car struct {
//	Vehicle
//}
//type Bus struct {
//	Vehicle
//}

func NewMotorcycle() *Vehicle {
	return &Vehicle{
		vType: MOTORCYCLE,
		vSize: 1,
		getRange: func(k int) []int {
			return getRange(0, k)
		},
	}
}
func NewCar() *Vehicle {
	return &Vehicle{
		vType: CAR,
		vSize: 1,
		getRange: func(k int) []int {
			return getRange(k/4, k)
		},
	}
}
func NewBus() *Vehicle {
	return &Vehicle{
		vType: BUS,
		vSize: 5,
		getRange: func(k int) []int {
			return getRange(k/4*3, k)
		},
	}
}
func NewParkingLot(n, m, k int) *ParkingLot {
	var lv []*Level
	for i := 0; i < n; i++ {
		lv = append(lv, &Level{
			n:      n,
			row:    m,
			column: k,
			spots:  map[string]*Vehicle{},
		})
	}
	return &ParkingLot{
		levels: lv,
	}
}
func (pl *ParkingLot) ParkVehicle(v *Vehicle) bool {
	for _, level := range pl.levels {
		if level.ParkVehicle(v) {
			return true
		}
	}
	return false
}

func (l *Level) ParkVehicle(v *Vehicle) bool {
	vaColumns := v.getRange(l.column)
	// 尝试遍历每列去停车
	for r := 0; r < l.row; r++ {
		foundSpots := 0
		var vRowCols []string
		// 每列该车的可停靠区域
		for _, c := range vaColumns {
			vRowColumn := fmt.Sprintf("%d,%d", r, c)
			if _, exists := l.spots[vRowColumn]; exists {
				foundSpots = 0
				vRowCols = nil
				continue
			}
			foundSpots++
			vRowCols = append(vRowCols, vRowColumn)

			if foundSpots == v.vSize {
				v.vLevel = l
				v.vRowColumns = vRowCols
				for _, vRowCol := range vRowCols {
					l.spots[vRowCol] = v
				}
				return true
			}
		}
	}
	return false
}

func (pl *ParkingLot) UnparkVehicle(v *Vehicle) {
	v.Unpark()
}
func (v *Vehicle) Unpark() {
	if v.vLevel != nil {
		for _, vrc := range v.vRowColumns {
			delete(v.vLevel.spots, vrc)
		}
		v.vLevel = nil
		v.vRowColumns = nil
	}
}

//	func (m Motorcycle) GetRange(k int) []int {
//		return getRange(0, k)
//	}
//
//	func (m Car) GetRange(k int) []int {
//		return getRange(k/4, k)
//	}
//
//	func (m Bus) GetRange(k int) []int {
//		return getRange(k/4*3, k)
//	}
func getRange(start, end int) []int {
	var rangeArray []int
	for i := start; i < end; i++ {
		rangeArray = append(rangeArray, i)
	}
	return rangeArray
}
